package com.e3.template.tgf;

import java.util.ArrayList;
import java.util.List;

import com.e3.template.model.TGFTreeModel;
import com.e3.web.core.client.ListenerManager;
import com.e3.web.core.client.TreeListener;
import com.e3.web.core.model.ModelHelper;
import com.e3.web.widget.client.BaseAction;
import com.e3.web.widget.client.MyMenuItem;
import com.e3.web.widget.client.MyTreePanel;
import com.e3.web.widget.model.MyTreeModel;
import com.extjs.gxt.ui.client.data.BaseTreeLoader;
import com.extjs.gxt.ui.client.data.DataProxy;
import com.extjs.gxt.ui.client.data.TreeLoader;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanelSelectionModel;
import com.google.gwt.user.client.Element;

public abstract class TGFTreePanel<D extends TGFTreeModel> extends LayoutContainer {
	
	protected ModelHelper<D> modelHelper = new ModelHelper<D>();
	
	protected ListenerManager<D> listenerManager = new ListenerManager<D>();
	
	private Component maskComponent;
	
	private MyTreePanel<D> treePanel;
	
	private TreeLoader<D> treeLoader;
	
	private TreeStore<D> treeStore;
	
	private TreePanelSelectionModel<D> treeSelectionModel;
	
	protected SelectionListener<MenuEvent> mnuSelectListener = new SelectionListener<MenuEvent>() {
		@Override
		public void componentSelected(MenuEvent ce) {
			ce.getSource();
			MyMenuItem item = (MyMenuItem)ce.getItem();
			onMnuEvent(item.getAction());
		}

	};
	
	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		this.setLayout(new FitLayout());
		
		ContentPanel cp = new ContentPanel(new FitLayout());
		cp.setHeaderVisible(false);
		cp.setSize(100, 400);
		
		cp.add(getTreePanel());
		
		add(cp);
	}
	
	public MyTreePanel<D> getTreePanel(){
		if(treePanel == null){
			treePanel = new MyTreePanel<D>(getTreeStore());
			
			treePanel.setDisplayProperty(getTreeDisplayFieldName());
			treePanel.setBorders(true);
			treePanel.setWidth(100);
			
			treePanel.setSelectionModel(getTreeSelectionModel());
			
		}
		return treePanel;
	}

	
	protected TreeStore<D> getTreeStore() {
		if(treeStore==null){	
			treeStore = new TreeStore<D>(getTreeLoader());
			treeStore.setModelComparer(modelHelper.getModelComparer());
			treeStore.setKeyProvider(modelHelper.getModelKeyProvider());
		}
		return treeStore;
	}
	
	protected TreeLoader<D> getTreeLoader(){
		if(treeLoader == null){
			treeLoader = createTreeLoader();
		}
		return treeLoader;
	}

	protected TreePanelSelectionModel<D> getTreeSelectionModel() {
		if(treeSelectionModel==null){
			treeSelectionModel = new TreePanelSelectionModel<D>();
			treeSelectionModel.addSelectionChangedListener(new SelectionChangedListener<D>() {   
				@Override
				public void selectionChanged(SelectionChangedEvent<D> se) {
					D model = se.getSelectedItem();
					onTreeDataSelected(model); 
				}
	        });   
		}
		return treeSelectionModel;
	}
	
	protected void onTreeDataSelected(D model) {
		if(model == null){
			return;
		}
		MyTreeModel tModel = (MyTreeModel)model;
		D pModel = getTreeStore().getParent(model);
		tModel.setParentModel(pModel);
		List<D> subModels = getTreeStore().getChildren(model);
		
		if(subModels!=null&&subModels.size()>0){
			for (D d : subModels) {
				((MyTreeModel)d).setParentModel(model);
			}
			listenerManager.notifyTreeDataSelected(model, subModels);
			return;
		}
		
		if(!tModel.hasChildren()){
			List<D> models = new ArrayList<D>(1);
			models.add(model);
			listenerManager.notifyTreeDataSelected(model, models);
			return;
		}
		
	}

	protected void onMnuEvent(BaseAction action) {
	}

	public void addTreeListener(TreeListener<D> listener){
		listenerManager.addTreeListener(listener);
	}
	
	public void setTreeContextMenu(Menu menu){
		beforeSetTreeContextMenu(menu);
		getTreePanel().setContextMenu(menu);
	}
	
	public void setMaskComponent(Component maskComponent) {
		this.maskComponent = maskComponent;
	}
	
	public Component getMaskComponent() {
		return maskComponent;
	}
	
	public void beforeSetTreeContextMenu(Menu menu){
		
	}
		
	protected void successLoadTreeChildren(D model,List<D> result){
		if(result!=null&&result.size()>0){
			for (D d : result) {
				((MyTreeModel)d).setParentModel(model);
			}
		}
		listenerManager.notifyTreeDataSelected(model, result);
	}

	public SelectionListener<MenuEvent> getMnuSelectListener() {
		return mnuSelectListener;
	}
	
	public void refreshTreeModel(D model){
		getTreePanel().updateTreeModel(model, true);
	}
	
	public void removeTreeNodes(List<D> models){
		getTreePanel().removeTreeNodes(models);
	}
	
	public List<D> getChildren(D pModel,boolean deep){
		return getTreeStore().getChildren(pModel, deep);
	}
	
	public boolean isRootNode(D model){
		List<D> roots = getTreeStore().getRootItems();
		if(roots!=null){
			for (D rm : roots) {
				if(rm.equals(model)){
					return true;
				}
			}
		}
		return false;
	}
	
	@SuppressWarnings("unchecked")
	protected TreeLoader<D> createTreeLoader(){
		return new BaseTreeLoader<D>(getTreeLoaderProxy()){
			public boolean hasChildren(D parent) {
				return ((MyTreeModel)parent).hasChildren();
			}

			@Override
			protected void onLoadFailure(Object loadConfig, Throwable t) {
				getMaskComponent().unmask();
				super.onLoadFailure(loadConfig, t);
			}
			
			@Override
			protected void onLoadSuccess(Object loadConfig,	List<D> result) {
				getMaskComponent().unmask();
				onTreeLoadSuccess((D)loadConfig,result);
				if(result == null){
					getTreePanel().setLeaf((D)loadConfig, true);
					return;
				}
				super.onLoadSuccess(loadConfig, result);
			}
		};
	}
	
	protected void onTreeLoadSuccess(D loadConfig, List<D> result) {
		
	}
	
	public abstract DataProxy<List<D>> getTreeLoaderProxy();

	public abstract String getTreeDisplayFieldName();
	
}
